package demo1;

import java.util.Objects;

//对象的打印，获取对象的信息
class Person{
    public String name;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public int age;

    @Override
    public String toString() {//这个时候重写了本地的toString的方法。所以发生了多态
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';//这种操作叫做对象的打印，也叫获取对象的信息
        /*return "wanghongyu";*/
    }

   /* public String toString() {
        return getClass().getName() + "@" + Integer.toHexString(hashCode());
        getclass().getName()其实是一个全路径
        Integer.toHexString(hashCode())其实是一个哈希值
    }*/

    /*public static String valueOf(Object obj) {//这个时候用object类来接受对象（object类是所有的类的父类），发生了动态绑定，从而调用子类的方法
        return (obj == null) ? "null" : obj.toString();
    }*/

    //重写equals方法

//    @Override
//    public boolean equals(Object obj) {
//        //return true;//这个时候看我们写的是什么，true，那么幼稚返回true，false也是同理
//        return false;
//    }



    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;// 向下转型，比较属性值,两者的属性是自己定义的，不是object类
        return age == person.age && Objects.equals(name, person.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }


//    @Override
//    public boolean equals(Object obj) {
//        if (obj == null) {//如果是被比较的对象是空类型
//            return false ;
//        }
//        if(this == obj) {//两者指向了一个对象的空间，那么获得的地址是一个，所以两者是一个
//            return true ;
//        }
//        // 不是Person类对象
//        if (!(obj instanceof Person)) {//判断person
//            return false ;
//        }
//        Person person = (Person) obj ; // 向下转型，比较属性值,两者的属性是自己定义的，不是object类
//        return this.name.equals(person.name) && this.age==person.age ;
//    }//这个就是手写的，上述的是编辑器帮我们生成的equals，两者的逻辑是一样的

}
public class Test1 {
    public static void main(String[] args) {
        Person person1 = new Person("张三",10);
        System.out.println(person1);
        Person person2 = new Person("张三",10);
        System.out.println(person2);
        System.out.println("=========");
        System.out.println(person1 == person2);//比较两者实例化后是不是一个person
        //结果是false
        //通过直接打印了它们的地址，发现两者的地址不同
        //所以这个时候比较的就是变量中的值
        System.out.println(person1.equals(person2));//通过equals方法来进行比较

        /*public boolean equals(Object obj) {
            return (this == obj);//这个this谁调用了equals方法就是this，那么上面person1就是this
        }*/
        //如何区分this引用，谁调用当前的方法，谁就是this

        Person person3 = person1;
        System.out.println(person3.equals(person1));
        System.out.println("===========");
        System.out.println(person1.hashCode());
        System.out.println(person2.hashCode());
        //如果我们没有重写hashcode，那么打印的是两者的哈希值
        //如果我们判断名字和姓名是一样，那么就不需要重复在开阔空间了，所以我们这个时候可以重写hashcode
        //所以我们重写的hashcode会发现某些对象出现在堆中同一个位置

        //后期讲到哈希表的时候便会知道（现实逻辑中的）如果两个一样的对象想放在同一个位置，此时我就可以利用重写hashcode这个方法来实现
        //比如身份证，名字，年龄一样这就是一样的，具体情况具体分析
    }


    //所以通过equals方法的比较，我们要明白：如果是以后自定义的类型，那么一定要记住重写equals方法和hashCode的方法
    //结论：比较对象中内容是否相同的时候，一定要重写equals方法。





    /*
    public String toString() {
        return getClass().getName() + "@" + Integer.toHexString(hashCode());
    }
    我们可以看到toString可以帮我们算到一个文件的路径，hashcode会帮我们算出一个地址以16进制输出
     */
    /*
    hashcode方法源码：

         public native int hashCode();

    该方法是一个native方法，底层是由C/C++代码写的。我们看不到。
    我们认为两个名字相同，年龄相同的对象，将存储在同一个位置，如果不重写hashcode()方法，我们可以来看示例
    代码：

    注意事项：两个对象的hash值不一样。
    像重写equals方法一样，我们也可以重写hashcode()方法。此时我们再来看看。

     */

    /*
    结论：
    1、hashcode方法用来确定对象在内存中存储的位置是否相同
    2、事实上hashCode() 在散列表中才有用，在其它情况下没用。在散列表中hashCode() 的作用是获取对象的
    散列码，进而确定该对象在散列表中的位置。

     */
}
